package org.hibernate.tool.ipan.connection;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.connection.ConnectionProviderFactory;
import org.hibernate.util.PropertiesHelper;
import org.hibernate.util.ReflectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JDBC链接管理器
 * 更换默认的DriverManagerConnectionProvider管理器，放弃使用默认链接池；
 * 使用Hibernate的配置信息来构建；
 * 
 * @author iPan
 * @version 2013-8-16
 */
public class NoPoolConnectionProvider implements ConnectionProvider {
	private String url;
	private Properties connectionProps;
	private Integer isolation;
	private int checkedOut = 0;
	private boolean autocommit = false;
	private Logger log = LoggerFactory.getLogger(getClass());

	public void configure(Properties props) throws HibernateException {

		String driverClass = props.getProperty(Environment.DRIVER);

		autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props, false);
		log.info("autocommit mode: " + autocommit);

		isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);
		if (isolation != null) {
			log.info("JDBC isolation level: " + Environment.isolationLevelToString(isolation.intValue()));
		}
		
		if (driverClass == null) {
			log.warn("no JDBC Driver class was specified by property " + Environment.DRIVER);
		} else {
			try {
				// trying via forName() first to be as close to DriverManager's
				// semantics
				Class.forName(driverClass);
			} catch (ClassNotFoundException cnfe) {
				try {
					ReflectHelper.classForName(driverClass);
				} catch (ClassNotFoundException e) {
					String msg = "JDBC Driver class not found: " + driverClass;
					log.error(msg, e);
					throw new HibernateException(msg, e);
				}
			}
		}

		url = props.getProperty(Environment.URL);
		if (url == null) {
			String msg = "JDBC URL was not specified by property " + Environment.URL;
			log.error(msg);
			throw new HibernateException(msg);
		}

		connectionProps = ConnectionProviderFactory.getConnectionProperties(props);

		log.info("using driver: " + driverClass + " at URL: " + url);
		// if debug level is enabled, then log the password, otherwise mask it
		if (log.isDebugEnabled()) {
			log.info("connection properties: " + connectionProps);
		} else if (log.isInfoEnabled()) {
			log.info("connection properties: " + PropertiesHelper.maskOut(connectionProps, "password"));
		}
	}

	public Connection getConnection() throws SQLException {
		if (log.isTraceEnabled()) {
			log.trace("total checked-out connections: " + checkedOut);
		}

		log.debug("opening new JDBC connection");
		Connection conn = DriverManager.getConnection(url, connectionProps);
		if (isolation != null) {
			conn.setTransactionIsolation(isolation.intValue());
		}
		if (conn.getAutoCommit() != autocommit) {
			conn.setAutoCommit(autocommit);
		}
		if (log.isDebugEnabled()) {
			log.debug("created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation());
		}
		if (log.isTraceEnabled()) {
			checkedOut++;
		}
		return conn;
	}

	public void closeConnection(Connection conn) throws SQLException {
		if (log.isDebugEnabled()) {
			checkedOut--;
		}
		log.debug("closing JDBC connection");
		if (conn != null) {
			conn.close();
		}
	}

	protected void finalize() {
		close();
	}

	public void close() {
	}

	/**
	 * @see ConnectionProvider#supportsAggressiveRelease()
	 */
	public boolean supportsAggressiveRelease() {
		return false;
	}
}
